<?php
/*
 * @Author: Wulala
 * @Date: 2025-04-08 11:46:09
 * @LastEditTime: 2025-04-11 16:15:06
 * @LastEditors: Wulala
 * @Description: 
 * @FilePath: \exchange\app\api\service\SignService.php
 * 可以输入预定的版权声明、个性签名、空行等
 */

namespace app\api\service;

use app\common\model\AppConfig as AppConfigModel;

// 验签服务类
/**
 * 模仿微信的签名验证类
 */
class SignService
{

    public static $stamp=120*1000;//时间戳过期时间----2分钟
 
    public static function verifySign($params)
    {  
        // 验证必传参数
        if (!isset($params['sign'])) {
            output_error('缺少签名参数');
        }
        if (!isset($params['timestamp'])) {
            output_error('缺少时间戳参数');
        }
        if (!isset($params['appid']) ) {
            output_error('缺少appid参数');
        }
        
        // 验证时间戳是否过期
        $timestamp = $params['timestamp'];
        if (abs(time()*1000 - $timestamp) >self::$stamp) {
            output_error('请求已过期');
        }
        
        // 获取客户端传来的签名
        $clientSign = $params['sign'];
        unset($params['sign']); // 签名参数不参与签名

        // 生成服务端签名
        $app_secret =AppConfigModel::where('appid', $params['appid'])->value('app_secret');
        $serverSign = self::generateSign($params, $app_secret);
        
        // 验证签名
        if ($clientSign !== $serverSign) {
            output_error('签名验证失败');
        }
        
        return true;
    }
    
    /**
     * 生成签名
     * @param array $params 参数数组
     * @param string $secret 密钥
     * @return string
     */
    protected static function generateSign(array $params, string $secret): string
    {
        // 过滤空值
        $params = array_filter($params, function($value) {
            return $value !== '' && $value !== null;
        });
        
        // 按key升序排序
        ksort($params);
        
        // 拼接字符串
        $string = '';
        foreach ($params as $key => $value) {
            $string .= $key . '=' . $value . '&';
        }
        $string = rtrim($string, '&');
        
        // 拼接密钥并生成签名
        $string .= '&app_secret='.$secret;

        // var_dump(md5($string));exit;

        // 使用md5加密（也可以使用sha1）
        return md5($string);
    }
}